/*
*********************************
	  SF2D Engine
*********************************

	By Julian Williams
	October 2, 2010
**********************************

	Description:

		PathComponent class that 
	lets entities move about a path 
	through a pre-determinded grid
***********************************
*/

#include "path_component.h"
#include "path_finder.h"

b2Vec2 PathComponent::grid_size;


PathComponent::PathComponent(void)
{
	target_pos.SetZero();
	current_node = 0;
	last_node = 0;
	target_timer = 200;
}



b2Vec2 PathComponent::GetGridSize()
{
	return grid_size;
}//EoF

void PathComponent::SetGridSize(const b2Vec2 &new_grid)
{
	grid_size = new_grid;
}//EoF


//--------------------
// reference counting
//--------------------

void PathComponent::AddRef()
{
	refCount++;
}



void PathComponent::Release()
{
	if( --refCount == 0 )
		delete this;
}


//-----------------------
// AngelScript functions
//-----------------------

static void PathComponentDefaultFactory(PathComponent *self)
{
	new(self) PathComponent();
}




//Wegistor wif scwipt endgwin
bool PathComponent::Register_With_ScriptEngine( asIScriptEngine *engine)
{
	int r = 0;

	// Register the type
	r = engine->RegisterObjectType("PathComponent", 0, asOBJ_REF); assert( r >= 0 );

	// Register the object operator overloads
	// Note: We don't have to register the destructor, since the object uses reference counting
	r = engine->RegisterObjectBehaviour("PathComponent", asBEHAVE_FACTORY, "PathComponent @f()", asFUNCTION(PathComponentDefaultFactory), asCALL_CDECL);	assert( r >= 0 );
	//r = engine->RegisterObjectBehaviour("string", asBEHAVE_FACTORY,    "string @f(const string &in)", asFUNCTION(StringCopyFactory), asCALL_CDECL); assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("PathComponent", asBEHAVE_ADDREF,  "void f()", asMETHOD(PathComponent, AddRef),  asCALL_THISCALL);					assert( r >= 0 );
	r = engine->RegisterObjectBehaviour("PathComponent", asBEHAVE_RELEASE, "void f()", asMETHOD(PathComponent, Release), asCALL_THISCALL);					assert( r >= 0 );


	// Register the object methods
	r = engine->RegisterObjectMethod("PathComponent", "vector2 GetTarget()", asMETHOD(PathComponent, GetTarget), asCALL_THISCALL);							assert( r >= 0 );
	r = engine->RegisterObjectMethod("PathComponent", "void SetTargetNode(int)", asMETHOD(PathComponent, SetTargetNode), asCALL_THISCALL);					assert( r >= 0 );
	r = engine->RegisterObjectMethod("PathComponent", "int GetTargetNode()", asMETHOD(PathComponent, GetTargetNode), asCALL_THISCALL);						assert( r >= 0 );
	r = engine->RegisterObjectMethod("PathComponent", "vector2 GetNodePosition(int)", asMETHOD(PathComponent, GetNodePosition), asCALL_THISCALL);			assert( r >= 0 );
	r = engine->RegisterObjectMethod("PathComponent", "void NextTarget()", asMETHOD(PathComponent, NextTarget), asCALL_THISCALL);							assert( r >= 0 );
	r = engine->RegisterObjectMethod("PathComponent", "int GetLastNode()", asMETHOD(PathComponent, GetLastNode), asCALL_THISCALL);							assert( r >= 0 );
	r = engine->RegisterObjectMethod("PathComponent", "int FindPath(vector2&,  vector2&)", asMETHOD(PathComponent, FindPath), asCALL_THISCALL);	assert( r >= 0 );
		
	
	r = engine->RegisterEnum("Path_Result"); assert( r >= 0 );
	r = engine->RegisterEnumValue("Path_Result", "NO_SOLUTION", 1 ); assert( r >= 0 );
	r = engine->RegisterEnumValue("Path_Result", "START_END_SAME", 2 ); assert( r >= 0 );
	r = engine->RegisterEnumValue("Path_Result", "SOLVED", 0); assert( r >= 0 );

	//Register Properties
	r = engine->RegisterObjectProperty("PathComponent", "int target_timer",		offsetof(PathComponent, target_timer));		assert( r >= 0 );



	if(r < 0)
	{
		cout << "Register Class Result: " << r << endl;
		return false;
	}

	return true;
}//EoF





//grab the next path in the array
b2Vec2 PathComponent::GetTarget()
{
	return target_pos;
}//EoF


b2Vec2 PathComponent::GetNodePosition(int path_offset)
{

	if(path_offset >= path.size())
	{
		cout << "[PATH COMPONENT]: \nfunc: SetTargetNode .\n"
			<< __FILE__ <<  "-" << __LINE__ << endl;

			path_offset = 0;
	}

	int x, y;
	Pather.NodeToXY( path[path_offset], &x, &y);

//Set its position acording to grid size (for screen)
	b2Vec2 position;
	position.x = (x*grid_size.x) + grid_size.x/2;
	position.y = (y*grid_size.y) + grid_size.y/2;

	return position;
}//EoF


void PathComponent::NextTarget()
{
	current_node++;
	SetTargetNode(current_node);
}//EoF



void PathComponent::SetTargetNode(int path_offset)
{
	//Make sure the current node isn't greater than the last node on the list

		current_node = (path_offset < last_node) ? path_offset : last_node;
		target_pos = GetNodePosition(current_node);
}//EoF


int PathComponent::GetTargetNode()
{
	return current_node;
}//EoF


int PathComponent::GetLastNode()
{
	return last_node;
}//EoF


int PathComponent::FindPath( const b2Vec2 &start, const b2Vec2 &end )
{

	///cout << "Before:\n";
	///cout << start.x << ", " << start.y << endl;
	///cout << end.x << ", " << end.y << endl;

	//Convert from Pixel positions to tile grid positions
	b2Vec2 new_start, new_end;
	new_start.x = (grid_size.x != 0) ? start.x / grid_size.x : 0;
	new_start.y = (grid_size.y != 0) ? start.y / grid_size.y : 0;

	new_end.x = (grid_size.x != 0) ? end.x / grid_size.x : 0;
	new_end.y = (grid_size.y != 0) ? end.y / grid_size.y : 0;

///	cout << "After:\n";
///	cout << start.x << ", " << start.y << endl;
///	cout << end.x << ", " << end.y << endl;

	float total_cost;

	//std::vector<void*> path;
	path.clear();

	pathShown.clear();

	vector<void*> newPath;

	int result = Pather.SolvePath(static_cast<int>(new_start.x), static_cast<int>(new_start.y), 
								  static_cast<int>(new_end.x), static_cast<int>(new_end.y), newPath, total_cost);
	
	//error handling
	switch(result)
	{
	case MicroPather::START_END_SAME:
		cout << "[PATH] - Start and End position is the same, terminating path finder...\n";
		break;

	case MicroPather::NO_SOLUTION:
		cout << "[PATH] - No solution :/ \nsorry :o\n";
		break;

	case MicroPather::SOLVED:
	//	cout << "[Path] - path found!\n";
		last_node = newPath.size()-1;
		path.swap(newPath);

		SetTargetNode(0);
		break;
	}


	
	return result;

}//EoF